home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung / Power-Programmierung (Tewi)(1994).iso / magazine / drdobbs / 1987 / 12 / holub / task.c < prev    next >
Text File  |  1987-12-21  |  55KB  |  574 lines

  1. #include <dos.h>                                                                              
  2. #include <stdarg.h>                                                                           
  3. #include <signal.h>                                                                           
  4. #include <tools/hardware.h>     /* #define for TIMR_CLK */                                    
  5. #include "kernel.h"                                                                           
  6.                                                                                               
  7. static int   Speedup_factor = 0;                                                              
  8. static long  Executed, Timed_out, Did_swap;                                                   
  9.                                                                                               
  10. #define max(a,b)  ((a) > (b) ? (a) : (b))                                                     
  11.                                                                                               
  12. /*------------------------------------------------------------                                
  13.  * Strings for error codes. Note that these are upside down                                   
  14.  * to compensate for the negative indexes                                                     
  15.  */                                                                                           
  16.                                                                                               
  17. static char     *msgs[] =                                                                     
  18. {                                                                                             
  19.     "Ctrl-Break or Ctrl-C"                           /* -10 */                                
  20.     "Stack overflow",                                /*  -9 */                                
  21.     "Delete would have caused a deadlock",           /*  -8 */                                
  22.     "Internal error",                                /*  -7 */                                
  23.     "No tasks to send message to",                   /*  -6 */                                
  24.     "Queue is full",                                 /*  -5 */                                
  25.     "Timeout",                                       /*  -4 */                                
  26.     "Illegal Argument",                              /*  -3 */                                
  27.     "Insufficient memory available",                 /*  -2 */                                
  28.     "Maximum number of tasks (32) already exists",   /*  -1 */                                
  29.     "No error"                                       /*   0 */                                
  30. };                                                                                            
  31.                                                                                               
  32. char **t_errlist = msgs + ((sizeof(msgs)/sizeof(*msgs)) -1);                                  
  33.                                                                                               
  34. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */                              
  35.                                                                                               
  36. t_iserr(x)                                                                                    
  37. {                                                                                             
  38.     return( -10 <= (x) && (x) < 0 );                                                          
  39. }                                                                                             
  40.                                                                                               
  41. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */                              
  42.                                                                                               
  43. t_perror( str, errcode )                                                                      
  44. char    *str;                                                                                 
  45. {                                                                                             
  46.     if( !t_iserr(errcode) && errcode != 0 )                                                   
  47.         t_printf( "%s status %d\n", str, errcode );                                           
  48.     else                                                                                      
  49.         t_printf( "%s %s\n", str, t_errlist[errcode] );                                       
  50. }                                                                                             
  51.                                                                                               
  52. /*------------------------------------------------------------*/                              
  53.                                                                                               
  54. static intr()                                                                                 
  55. {                                                                                             
  56.     t_stop( TE_KILL );                                                                        
  57. }                                                                                             
  58.                                                                                               
  59. /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */                              
  60.                                                                                               
  61. int     t_start( speedup_factor )                                                             
  62. {                                                                                             
  63.     /* Start multitasking. At least one task must have                                        
  64.      * been created prior to this call. The speedup factor                                    
  65.      * determines the system clock-tick rate. A value of 1                                    
  66.      * gives the default rate of roughly 18.2 times a second                                  
  67.      * (once every 55 milliseconds, more or less). A                                          
  68.      * speedup_factor of 2 gives twice that speed: 36.4 ticks                                 
  69.      * per second, one every 27 milliseconds or thereabouts.                                  
  70.      * Speeding up the clock rate shouldn't affect the DOS                                    
  71.      * clock. Nonetheless, it's safest if the speedup factor                                  
  72.      * is a power of two.                                                                     
  73.      *                                                                                        
  74.      * If the speedup factor is 0 then the system is                                          
  75.      * nonpreemptive. You'll have to use t_yield(), t_send(),                                 
  76.      * and t_wait() to change contexts.                                                       
  77.      *                                                                                        
  78.      * Control passes imediately to the highest priority task.                                
  79.      * Control will automatically pass back to the calling                                    
  80.      * subroutine when all tasks have been deleted. The task                                  
  81.      * is actually started in _t_shazam(), declared in swap.asm.                              
  82.      *                                                                                        
  83.      * Normal return values:                                                                  
  84.      *                                                                                        
  85.      *  TE_NOTASKS      No tasks exist, multitasking not                                      
  86.      *                  started;                                                              
  87.      *                                                                                        
  88.      *  TE_DEADLOCK     A task deleted itself and it's the                                    
  89.      *                  only active task in the system. Other                                 
  90.      *                  tasks exist but they're all pending                                   
  91.      *                  on queues.                                                            
  92.      *                                                                                        
  93.      *  TE_NOERR        All tasks have been deleted normally,                                 
  94.      *                  no tasks are waiting on queues.                                       
  95.      *                                                                                        
  96.      *  TE_STACK        Task stack overflow.                                                  
  97.      *                                                                                        
  98.      * If TE_NOERR is returned, then all memory allocated to                                  
  99.      * tasks will have been saved, otherwise, if one of the                                   
  100.      * above errors was returned, T_active will point at the                                  
  101.      * TCB of the offending task.                                                             
  102.      *                                                                                        
  103.      * Other return values are possible if a task calls t_stop()                              
  104.      * directly. The argument passed to t_stop() is returned by                               
  105.      * t_start(). The process is analogous to the value of                                    
  106.      * exit(), which doesn't return and who's argument is                                     
  107.      * passed back to a wait() call in the parent process. Note                               
  108.      * that the TCB pointed to by T_active will not be free()ed                               
  109.      * unless TE_NOERR (0) is returned.                                                       
  110.      */                                                                                       
  111.                                                                                               
  112.     Speedup_factor = speedup_factor;                                                          
  113.                                                                                               
  114.     if( !pq_del( T_tasks, &T_active ) )                                                       
  115.         return TE_NOTASKS;                                                                    
  116.                                                                                               
  117.     if( speedup_factor > 0 )                                                                  
  118.     {                                                                                         
  119.         t_cli();                                                                              
  120.         _t_speedup( speedup_factor );                                                         
  121.     }                                                                                         
  122.                                                                                               
  123.     signal( SIGINT, intr );                                                                   
  124.                                                                                               
  125.     _t_shazam();                                                                              
  126.     return TE_INTERNAL;         /* Shouldn't ever get here */                                 
  127. }                                                                                             
  128.                                                                                               
  129. /*------------------------------------------------------------*/                              
  130.                                                                                               
  131. int     t_second()                                                                            
  132. {                                                                                             
  133.     /* Returns the number of system clock ticks in a                                          
  134.      * second, given the speedup factor passed to t_start().                                  
  135.      * Returns 0 if the speedup factor was 0. In this case                                    
  136.      * a t_wait() call will never time out.                                                   
  137.      */                                                                                       
  138.                                                                                               
  139.     return (TIMR_CLK / 65536) * Speedup_factor ;                                              
  140. }                                                                                             
  141.                                                                                               
  142. /*------------------------------------------------------------*/                              
  143.                                                                                               
  144. TCB     *t_create( subr, tag, priority, stack_size, ... )                                     
  145.                                                                                               
  146. int      (*subr)();     /* Subroute that forms main module */                                 
  147. char     *tag;          /* String used to identify TCB     */                                 
  148. unsigned priority;      /* Priority                        */                                 
  149. int      stack_size;    /* Stack size (in 2-byte words)    */                                 
  150. {                                                                                             
  151.     /* Creates a new task. Subr is a pointer to the main()                                    
  152.      * subroutine for the task.                                                               
  153.      *                                                                                        
  154.      * Priorities must be in the range 0-255. 255 is the                                      
  155.      * highest. If more than one task has the same priority,                                  
  156.      * they are executed in a round-robin                                                     
  157.      * fashion. Forces a reschedule if tasking is active.                                     
  158.      *                                                                                        
  159.      * Arguments may be passed to the subroutine at startup.                                  
  160.      * That is, a NULL-terminated list of pointer-sized                                       
  161.      * arguments follow stack_size in the t_create() call.                                    
  162.      * These are passed to the subroutine in the normal way.                                  
  163.      * For example:                                                                           
  164.      *                                                                                        
  165.      * foo( a, b, c ) int a, b, c; {}                                                         
  166.      * t_create( foo, "foo" 10, 128, doo, wha, ditty, NULL);                                  
  167.      *                                                                                        
  168.      * starts up foo() as a task at priority 10 with a                                        
  169.      * 128-byte stack. Doo, wha, and ditty are passed                                         
  170.      * to foo as arguments a, b, and c. Note that the                                         
  171.      * arguments use 6 of the 128 bytes in the stack                                          
  172.      * (two for each argument). The "foo" tag is just                                         
  173.      * used for identification purposes in debugging.                                         
  174.      * It can be any string.                                                                  
  175.      *                                                                                        
  176.      * Note that a few Microsoft functions (like printf)                                      
  177.      * use up inordinate amounts of stack. If you're going                                    
  178.      * to call Microsoft library routines, you'll need                                        
  179.      * at least 1K bytes of stack (stack_size==512) per                                       
  180.      * task.                                                                                  
  181.      *                                                                                        
  182.      * A pointer to the created TCB is returned normally.                                     
  183.      * Error return values are:                                                               
  184.      *                                                                                        
  185.      * TE_TOOMANY Maximum number of tasks already exists                                      
  186.      * TE_NOMEM   Insufficient memory available                                               
  187.      */                                                                                       
  188.                                                                                               
  189.     TCB     *t;                                                                               
  190.     struct  SREGS segs;                                                                       
  191.     int     pq_cmp();                                                                         
  192.     int     pq_swap();                                                                        
  193.     va_list argptr;                                                                           
  194.     void    *arg;                                                                             
  195.     void    *malloc();                                                                        
  196.                                                                                               
  197.     va_start( argptr, stack_size );                                                           
  198.                                                                                               
  199.     if( ++T_numtasks > T_MAXTASK )                                                            
  200.         return (TCB *) TE_TOOMANY;                                                            
  201.                                                                                               
  202.     t_block();                                                                                
  203.                                                                                               
  204.     /*  Allocate the stack, converting stack_size to bytes.                                   
  205.      *  I'm requesting one more cell than specified in order                                  
  206.      *  to make room for the error return address, below                                      
  207.      *  [stack[0] is included in the sizeof(TCB)]. The minimum                                
  208.      *  stack size is 20 words, this gives us enough for a                                    
  209.      *  context swap plus a little slop.                                                      
  210.      */                                                                                       
  211.                                                                                               
  212.     stack_size = max( stack_size, 20 );                                                       
  213.                                                                                               
  214.     if( !(t = (TCB *) malloc(sizeof(TCB)+(stack_size*sizeof(void*)) )))                       
  215.     {                                                                                         
  216.         t_release();                                                                          
  217.         return (TCB *) TE_NOMEM;                                                              
  218.     }                                                                                         
  219.                                                                                               
  220.     /* Create the active queue if necessary, then initialize                                  
  221.      * the TCB. The stack pointer is initialized to point                                     
  222.      * just past the end of the stack (rather than to the                                     
  223.      * last cell) because a push uses a predecrement. The                                     
  224.      * PC points at the subroutine. Uninitiailzed registers                                   
  225.      * are unimportant, but will contain 0. The stack area                                    
  226.      * is initialized to the pattern a5a5a5a5.... so that                                     
  227.      * we can look it with a debugger and see what's been                                     
  228.      * used. 0 is no good for this purpose because 0 is                                       
  229.      * a likely thing to be pushed on the stack.                                              
  230.      */                                                                                       
  231.                                                                                               
  232.     if( !T_tasks )                                                                            
  233.         T_tasks = pq_create( T_MAXTASK, sizeof(TCB *),                                        
  234.                                     pq_cmp, pq_swap, NULL);                                   
  235.     segread( &segs );                                                                         
  236.                                                                                               
  237.     memset( t,        0x0,  sizeof(TCB) - sizeof(void*) );                                    
  238.     memset( t->stack, 0xa5, stack_size  * sizeof(void*) );                                    
  239.                                                                                               
  240.     t->sp         = t->stack +  ++stack_size;                                                 
  241.     t->ss         = segs.ds  ;  /* Stacks are in data seg */                                  
  242.     t->initial_sp = t->sp    ;                                                                
  243.     t->priority   = priority ;                                                                
  244.     t->timestamp  = T_clock  ;                                                                
  245.     t->tag        = tag      ;                                                                
  246.                                                                                               
  247.     /* Initialize the stack, First pretend that we've                                         
  248.      * already called the initial subroutine by pushing                                       
  249.      * the arguments, and t_stop as a dummy return address.                                   
  250.      * The task shouldn't return, but if it does, t_stop                                      
  251.      * seems like a reasonable thing to call, even though                                     
  252.      * it will return garbage.                                                                
  253.      * The last 11 things are the initial context.                                            
  254.      * They'll be popped as part of the context swap.                                         
  255.      */                                                                                       
  256.                                                                                               
  257.     while( arg = va_arg(argptr, void*) )                                                      
  258.         *--(t->sp) = arg;                                                                     
  259.                                                                                               
  260.     *--(t->sp) = t_stop;        /* Vector to t_stop */                                        
  261.     *--(t->sp) = 0;             /* flags*/                                                    
  262.     *--(t->sp) = segs.cs;       /* cs   */                                                    
  263.     *--(t->sp) = subr;          /* ip   */                                                    
  264.     *--(t->sp) = 0;             /* ax   */                                                    
  265.     *--(t->sp) = 0;             /* bx   */                                                    
  266.     *--(t->sp) = 0;             /* cx   */                                                    
  267.     *--(t->sp) = 0;             /* dx   */                                                    
  268.     *--(t->sp) = 0;             /* si   */                                                    
  269.     *--(t->sp) = 0;             /* di   */                                                    
  270.     *--(t->sp) = 0;             /* bp   */                                                    
  271.     *--(t->sp) = segs.ds;       /* ds   */                                                    
  272.     *--(t->sp) = segs.es;       /* es   */                                                    
  273.                                                                                               
  274.     if( T_active  &&  T_PRIORITY( t, T_active ) <= 0 )                                        
  275.     {                                                                                         
  276.         pq_ins( T_tasks, &T_active );                                                         
  277.         _t_swap_in( t );                                                                      
  278.     }                                                                                         
  279.     else                                                                                      
  280.     {                                                                                         
  281.         pq_ins( T_tasks, &t );                                                                
  282.         t_release();                                                                          
  283.     }                                                                                         
  284.                                                                                               
  285.     return t;                                                                                 
  286. }                                                                                             
  287.                                                                                               
  288. /*------------------------------------------------------------*/                              
  289.                                                                                               
  290. static TCB      *del_fm_queues( task )                                                        
  291. TCB             *task;                                                                        
  292. {                                                                                             
  293.         /* Traverse the queue list and if the task is waiting                                 
  294.          * for a message, delete it from the queue                                            
  295.          * and return a pointer to it, otherwise return NULL.                                 
  296.          */                                                                                   
  297.                                                                                               
  298.         T_QUEUE *q;                                                                           
  299.         TCB     *t, **prev ;                                                                  
  300.                                                                                               
  301.         for( q = T_queues; q ; q = q->next )                                                  
  302.         {                                                                                     
  303.             prev = &q->task_h;                                                                
  304.                                                                                               
  305.             for( t = q->task_h; t; prev = &t->next, t = t->next)                              
  306.             {                                                                                 
  307.                 if( t == task )                                                               
  308.                 {                                                                             
  309.                     *prev = t->next ;                                                         
  310.                     return t;                                                                 
  311.                 }                                                                             
  312.             }                                                                                 
  313.         }                                                                                     
  314.                                                                                               
  315.         return NULL;                                                                          
  316. }                                                                                             
  317.                                                                                               
  318. /*------------------------------------------------------------*/                              
  319.                                                                                               
  320. int     t_chg_priority( tp, new_priority )                                                    
  321. TCB     *tp;                                                                                  
  322. int     new_priority;                                                                         
  323. {                                                                                             
  324.     /* Change priority for indicated task. Forces a reschedule.                               
  325.      * If the task was waiting on a message, it is immediately                                
  326.      * timed out and put back on the active list. A task may                                  
  327.      * change it's own priority.                                                              
  328.      *                                                                                        
  329.      * Return values:                                                                         
  330.      *                                                                                        
  331.      * TE_NOERR                                                                               
  332.      * TE_BADARG        Task doesn't exist;                                                   
  333.      */                                                                                       
  334.                                                                                               
  335.     int   rval = TE_NOERR;                                                                    
  336.     TCB   *deleted;                                                                           
  337.     int   pq_rm_cmp();                                                                        
  338.                                                                                               
  339.     if( new_priority > 255 )                                                                  
  340.         return TE_BADARG;                                                                     
  341.                                                                                               
  342.     t_block();                                                                                
  343.                                                                                               
  344.     if( tp == T_active )                                                                      
  345.     {                                                                                         
  346.         T_active->priority = new_priority;                                                    
  347.         t_yield();                                                                            
  348.     }                                                                                         
  349.     else                                                                                      
  350.     {                                                                                         
  351.         if( !pq_remove( T_tasks, &deleted, pq_rm_cmp, tp ) )                                  
  352.             if( deleted = del_fm_queues( tp ) )                                               
  353.             {                                                                                 
  354.                 deleted->status   = TS_TIMEOUT;                                               
  355.                 deleted->msg      = NULL;                                                     
  356.             }                                                                                 
  357.             else                                                                              
  358.                 return TE_BADARG;                                                             
  359.                                                                                               
  360.         deleted->priority = new_priority;                                                     
  361.         pq_ins( T_tasks, &deleted );                                                          
  362.         t_yield();                                                                            
  363.     }                                                                                         
  364. }                                                                                             
  365.                                                                                               
  366. /*------------------------------------------------------------*/                              
  367.                                                                                               
  368. int     t_delete( task )                                                                      
  369. TCB     *task;                                                                                
  370. {                                                                                             
  371.     /* Delete task created with previous t_create() call and                                  
  372.      * free all memory associated with task. Note that                                        
  373.      * malloced() memory is not freed, only the memory that                                   
  374.      * t_create() allocated to begin with. A task may delete                                  
  375.      * itself. Forces a reschedule.                                                           
  376.      *                                                                                        
  377.      * Return values:                                                                         
  378.      *                                                                                        
  379.      *  TE_BADARG       Task doesn't exist                                                    
  380.      *  TE_NOERR                                                                              
  381.      *                                                                                        
  382.      * T_stop is called automatically when the only active                                    
  383.      * task deletes itself. See t_start() for an explanation                                  
  384.      * of the return stati.                                                                   
  385.      *                                                                                        
  386.      * For convenience, a task may delete itself with a                                       
  387.      * t_delete(NULL) call.                                                                   
  388.      */                                                                                       
  389.                                                                                               
  390.     TCB         *deleted;                                                                     
  391.     static TCB  garbage;                                                                      
  392.     int         pq_rm_cmp();                                                                  
  393.                                                                                               
  394.     t_block();                                                                                
  395.                                                                                               
  396.     if( T_active == task  || task == NULL )                                                   
  397.     {                                                                                         
  398.         /* Delete the current task                                                            
  399.          * Note that the t_install() call below will not                                      
  400.          * return. It replaces the current task with the new                                  
  401.          * one, a pointer to which is in "deleted."                                           
  402.          */                                                                                   
  403.                                                                                               
  404.         if( !pq_del( T_tasks, &deleted) )                                                     
  405.             t_stop( T_numtasks <= 1 ? TE_NOERR : TE_DEADLOCK );                               
  406.         else                                                                                  
  407.         {                                                                                     
  408.             --T_numtasks;                                                                     
  409.             _t_install( deleted );                                                            
  410.         }                                                                                     
  411.     }                                                                                         
  412.     else                                                                                      
  413.     {                                                                                         
  414.         /* Delete a task that's not active. pq_remove tries                                   
  415.          * to get it from the active list. If that's not                                      
  416.          * successful, del_fm_queues() scans the queues looking                               
  417.          * for it. If that's not successfule, TE_BADARG is                                    
  418.          * returned.                                                                          
  419.          */                                                                                   
  420.                                                                                               
  421.         if( pq_remove( T_tasks, &deleted, pq_rm_cmp, task ) )                                 
  422.             free( deleted );                                                                  
  423.                                                                                               
  424.         else if( deleted = del_fm_queues(task) )                                              
  425.             free( deleted );                                                                  
  426.         else                                                                                  
  427.         {                                                                                     
  428.             t_release();                                                                      
  429.             return TE_BADARG ;                                                                
  430.         }                                                                                     
  431.                                                                                               
  432.         if( --T_numtasks <= 0 )    /* Deleted the only task */                                
  433.             t_stop( TE_NOERR );                                                               
  434.     }                                                                                         
  435.                                                                                               
  436.     t_release();                                                                              
  437.     return TE_NOERR;                                                                          
  438. }                                                                                             
  439.                                                                                               
  440. /*------------------------------------------------------------*/                              
  441.                                                                                               
  442. static  pq_cmp( task1, task2 )                                                                
  443. TCB     **task1, **task2;                                                                     
  444. {                                                                                             
  445.     return T_PRIORITY( *task1, *task2 );                                                      
  446. }                                                                                             
  447.                                                                                               
  448. static  pq_swap( task1, task2 )                                                               
  449. TCB     **task1, **task2;                                                                     
  450. {                                                                                             
  451.     TCB *tmp;                                                                                 
  452.                                                                                               
  453.     tmp    = *task1;                                                                          
  454.     *task1 = *task2;                                                                          
  455.     *task2 = tmp;                                                                             
  456. }                                                                                             
  457.                                                                                               
  458. static pq_rm_cmp( task1, item )                                                               
  459. TCB     **task1;                                                                              
  460. TCB     *item;                                                                                
  461. {                                                                                             
  462.     return !( *task1 == item );                                                               
  463. }                                                                                             
  464.                                                                                               
  465. /*------------------------------------------------------------*/                              
  466.                                                                                               
  467. static outc(c)                                                                                
  468. {                                                                                             
  469.     if( c == '\n' )                                                                           
  470.         putch('\r');                                                                          
  471.                                                                                               
  472.     putch(c);                                                                                 
  473. }                                                                                             
  474.                                                                                               
  475. t_printf( fmt )                                                                               
  476. char    *fmt;                                                                                 
  477. {                                                                                             
  478.     /* The doprnt() function used here is from: Allen Holub,                                  
  479.      * The C Companion (Englewood Cliffs: Prentice-Hall,                                      
  480.      * 1987). You can also use the ANSI vprintf(). Note                                       
  481.      * that the Microsoft version of vprintf() uses A LOT                                     
  482.      * of stack. If you're using vprintf, your tasks should                                   
  483.      * have at least 1K bytes of stack.                                                       
  484.      */                                                                                       
  485.                                                                                               
  486.     va_list     args;                                                                         
  487.                                                                                               
  488.     va_start(args, fmt);                                                                      
  489.                                                                                               
  490.     t_block();                                                                                
  491.     doprnt(outc, 0, fmt, args); /* vprintf( fmt, args ); */                                   
  492.     t_release();                                                                              
  493. }                                                                                             
  494.                                                                                               
  495. /*------------------------------------------------------------*/                              
  496.                                                                                               
  497. t_sstats()                                                                                    
  498. {                                                                                             
  499.     /* Print various scheduler related statistics. This routine                               
  500.      * should not be called from a task (because it uses printf).                             
  501.      */                                                                                       
  502.                                                                                               
  503.     printf("\nScheduler called %ld times: %ld Tasks timed_out, "                              
  504.                                         "%ld context swaps\n",                                
  505.                                Executed, Timed_out, Did_swap );                               
  506. }                                                                                             
  507.                                                                                               
  508. /*------------------------------------------------------------*/                              
  509.                                                                                               
  510. #pragma check_stack-                                                                          
  511.                                                                                               
  512. TCB *_t_reschedule()                                                                          
  513. {                                                                                             
  514.     static T_QUEUE      *q;                                                                   
  515.     static TCB          *t, **prev ;                                                          
  516.                                                                                               
  517.     /* Workhorse function called by the schedular                                             
  518.      * (timer-interrupt service routine).                                                     
  519.      *                                                                                        
  520.      * Scan all the queues, checking for timed-out tasks. If                                  
  521.      * you find one, remove it from the queue and add it to                                   
  522.      * the active list.                                                                       
  523.      *                                                                                        
  524.      * Modify T_active to point at the next task to activate.                                 
  525.      * (the original T_active if no change).                                                  
  526.      */                                                                                       
  527.                                                                                               
  528.     ++Executed;                                                                               
  529.                                                                                               
  530.     _t_sus_chkstk();            /* Stack probes off for the nonce */                          
  531.                                                                                               
  532.     for( q = T_queues; q ; q = q->next )                                                      
  533.     {                                                                                         
  534.         prev = &(q->task_h);                                                                  
  535.                                                                                               
  536.         for( t = q->task_h ; t ; )                                                            
  537.         {                                                                                     
  538.             if( --(t->wait) <= 0 )                                                            
  539.             {                                                                                 
  540.                 ++Timed_out;                                                                  
  541.                 *prev     = t->next ;                                                         
  542.                 t->msg    = NULL ;                                                            
  543.                 t->status = TE_TIMEOUT;                                                       
  544.                 pq_ins( T_tasks, &t );                                                        
  545.             }                                                                                 
  546.                                                                                               
  547.             prev = &(t->next);                                                                
  548.             t    =   t->next ;                                                                
  549.         }                                                                                     
  550.     }                                                                                         
  551.                                                                                               
  552.     /* Check the highest-priority element of the queue.                                       
  553.      * If it's not higher than the current task, do nothing.                                  
  554.      * Otherwise do a context swap. pq_replace will                                           
  555.      * extract the highest priority object from the active                                    
  556.      * list and put it into t, simultaneously putting                                         
  557.      * T_active into the list.                                                                
  558.      */                                                                                       
  559.                                                                                               
  560.     T_active->timestamp = ++T_clock ;                                                         
  561.                                                                                               
  562.     if( t = *(  (TCB **) pq_look(T_tasks)) )                                                  
  563.     {                                                                                         
  564.         if( T_PRIORITY(t, T_active)  >= 0 )                                                   
  565.         {                                                                                     
  566.             ++Did_swap;                                                                       
  567.             pq_replace( T_tasks, &t, &T_active );                                             
  568.             T_active = t ;                                                                    
  569.         }                                                                                     
  570.     }                                                                                         
  571.                                                                                               
  572.     _t_rst_chkstk();            /* Stack probes on again */                                   
  573. }                                                                                             
  574. #pragma check_stack+